/* TCSS 590A - Cybernetics and Systems
 * Group Project - Modeling
 * By Barry Jones, Naren Meadem, Michael Pitts, Yuan Tao
 * Fall 2012, University of Washington, Tacoma
 */
package model;

import java.math.BigDecimal;
import java.math.RoundingMode;

import output.OutPut;


/**
 * The very simple model that Interest Rate, Wage and Cost are constant.
 * Checking savingsAccount keeps 0 after paying costs.
 * @author Yuan Tao
 * @version Nov 14, 2012
 */

public class SimplestModel implements Model
{
	/** The interest rate.*/
	private double  my_interest_rate;
	
	/** The wage constant.*/
	private long my_wages;
	
	/** The costs constant.*/
	private long my_costs;
	
	/** The money in the saving savingsAccount.*/
	private long my_savings;
	
	/**The decimal part of saving.*/
	private double my_savings_fraction;
	
	/** The money in the checking savingsAccount.*/
	private long my_checkings;
	
	/** The output destination.*/
	private final OutPut my_out;// = new OutPutStream(System.out);
	
	/** These two variable just make sure the program doesn't run infinite times.
	 * They can be deleted when the end point is explicit.*/
	
	/**The count of running times.*/
	private int my_time = 0;
	
	/**The boundary to end the model.*/
	private final int my_boundary = 20;
	
	
	/**
	 * This function gives a decimal precision setting of 2.
	 * @param the_data is the number to be transfered to 2 decimal precision.
	 * @return the 2 decimal place double number.
	 */
	public double DecimalAccuracy(double the_data)
	{
		BigDecimal bg = new BigDecimal(the_data);
		double the_result = bg.setScale(2,RoundingMode.HALF_UP).doubleValue();
		return the_result;
	}
	
	/**
	 * Constructor it initiate all the variables in our model and output the initial state and table title.
	 * @param theInterest is the initial state of saving interest.
	 * @param theSaving is the initial saving amount.
	 * @param theWage is the initial wages.
	 * @param theCost is the initial costs.
	 * @param the_output is output.
	 */
	public SimplestModel(double theInterest, long theSaving, long theWage, long theCost, final OutPut the_output)
	{
		my_interest_rate = theInterest;
		my_wages = theWage;
		my_costs = theCost;
		/**Checking savingsAccount has the same amount to costs.*/
		my_checkings = theCost;
		my_savings = theSaving;		
		my_out = the_output;
		my_savings_fraction = 0;
		
		/** Print the all constants' value and table title.*/
		String[] output_string =  {"Initial State:","Interest Rate","Savings", "Wages", "Costs"};
		my_out.out(output_string);
		my_out.newLine();
		double[] output_data = {theInterest, theSaving, theWage, theCost};
		my_out.out(output_data);
		my_out.newLine();
		String[] output_title = {"Time", "Interest", "Savings","Wages", "Costs","Checkings","Final savings"};
		my_out.out(output_title);
	}
	
	
	/**
	 * It builds a default model as our excel does.
	 * All variables are hard code constants.
	 * For test using.
	 * @param the_output is the output.
	 */
	public SimplestModel(final OutPut the_output)
	{		
		this(0.08,1000,300,50,the_output);		
	}
	
	@Override public boolean runOne()
	{
		my_time++;
		if(my_costs > my_savings) //When the system attends to spend more money than it has, it corrupts and terminate.
		{
			my_out.newLine();
			my_out.out("Your costs are too high!  You are facing bankruptcy! ");
			my_out.newLine();
			my_out.close();
			return false;
		}		
		else if(my_time > my_boundary) // Merely setting an end boundary.
		{
			my_out.close();
			return false;
		}
		else //Do computation based on excel equation. I assume that the checking savingsAccount remains 0 every time.
		{		
			double savings = my_savings+my_savings_fraction;
			double finalSavings = savings * my_interest_rate + savings + my_wages - my_costs;
			finalSavings = DecimalAccuracy(finalSavings);
			
			double[] the_data = {my_interest_rate, savings, my_wages, my_costs,my_checkings,finalSavings};
			my_out.newLine();
			my_out.out(my_time);
			my_out.delineate();
			my_out.out(the_data);
			my_savings = (long)finalSavings;
			my_savings_fraction = finalSavings - my_savings;
			return true;
		}
	}
	
	

}
